package com.yxj.lib_camerax;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.AspectRatio;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.Preview;
import androidx.camera.core.VideoCapture;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;

import com.google.common.util.concurrent.ListenableFuture;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 自定义一个相机view
 */
public class CameraXView extends FrameLayout {
    // 声明一个上下文对象
    private Context mContext;
    // 声明一个预览视图对象
    private PreviewView mCameraPreview;
    // 声明一个摄像头选择器
    private CameraSelector mCameraSelector;
    // 声明一个预览对象
    private Preview mPreview;
    // 声明一个相机提供器
    private ProcessCameraProvider mCameraProvider;
    // 声明一个图像捕捉器
    private ImageCapture mImageCapture;
    // 声明一个视频捕捉器
    private VideoCapture mVideoCapture;
    // 声明一个线程池对象
    private ExecutorService mExecutorService;
    // 声明一个生命周期拥有者
    private LifecycleOwner mOwner;
    // 摄像头类型
    private int mCameraType = CameraSelector.LENS_FACING_BACK;
    // 宽高比例
    private int mAspectRatio = AspectRatio.RATIO_16_9;
    // 闪光灯模式
    private int mFlashMode = ImageCapture.FLASH_MODE_AUTO;
    // 媒体保存目录
    private String rootPath;
    /**
     * 拍照
     */
    public final static int MODE_PHOTO = 1;
    /**
     * 摄像
     */
    public final static int MODE_VIDEO = 2;
    /**
     * 停止回调
     */
    private OnStopListener mStopListener;

    private final Handler mHandler = new Handler();

    public interface OnStopListener {

        void onStop(int code, String msg);
    }

    public CameraXView(@NonNull Context context) {
        this(context, null);
    }

    public CameraXView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CameraXView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        mCameraPreview = new PreviewView(mContext); // 创建一个预览视图
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        mCameraPreview.setLayoutParams(params);
        addView(mCameraPreview); // 把预览视图添加到界面上
        mExecutorService = Executors.newSingleThreadExecutor(); // 创建一个单线程线程池
        setRootPath(Environment.getDownloadCacheDirectory().getAbsolutePath());
    }



    /**
     * 设置存储位置
     *
     * @param path
     */
    public void setRootPath(String path) {
        if (!isAndroid10()) {
            //android10 以下走这里
            rootPath = path + File.separator + "Pictures";
            File file = new File(rootPath);
            if (!file.exists()) {
                file.mkdirs();
            }
        } else {
            rootPath = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath();
        }
    }



    /**
     * android 10
     *
     * @return
     */
    public boolean isAndroid10() {
        return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
                && getContext().getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q);
    }



    /**
     * 摄像头类型  前置或后置
     * 前置   CameraSelector.LENS_FACING_FRONT;
     * 后置   CameraSelector.LENS_FACING_BACK;
     *
     * @param mCameraType
     */
    public void setCameraType(int mCameraType) {
        this.mCameraType = mCameraType;
        resetCamera();
    }


    /**
     * 切换前置还是后置
     */
    public void switchCamera() {
        if (mCameraType == CameraSelector.LENS_FACING_BACK) {
            mCameraType = CameraSelector.LENS_FACING_FRONT;
        } else {
            mCameraType = CameraSelector.LENS_FACING_BACK;
        }
        setCameraType(mCameraType);
    }


    /**
     * 打开相机
     *
     * @param owner
     * @param sl
     */
    public void openCamera(LifecycleOwner owner, OnStopListener sl) {
        mOwner = owner;
        mStopListener = sl;
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                initCamera();
            }
        });
    }


    /**
     * 初始化相机
     */
    private void initCamera() {
        ListenableFuture<ProcessCameraProvider> future = ProcessCameraProvider.getInstance(mContext);
        future.addListener(() -> {
            try {
                mCameraProvider = future.get();
                resetCamera(); // 重置相机
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, ContextCompat.getMainExecutor(mContext));
    }


    /**
     * 重置相机
     */
    private void resetCamera() {
        int rotation = mCameraPreview.getDisplay().getRotation();
        // 构建一个摄像头选择器
        mCameraSelector = new CameraSelector.Builder().requireLensFacing(mCameraType).build();
        // 构建一个预览对象
        mPreview = new Preview.Builder()
                .setTargetAspectRatio(mAspectRatio) // 设置宽高比例
                .build();
        // 构建一个图像捕捉器
        mImageCapture = new ImageCapture.Builder()
                .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) // 设置捕捉模式
                .setTargetRotation(rotation) // 设置旋转角度
                .setTargetAspectRatio(mAspectRatio) // 设置宽高比例
                .setFlashMode(mFlashMode) // 设置闪光模式
                .build();
        bindCamera(MODE_PHOTO); // 绑定摄像头
        // 设置预览视图的表面提供器
        mPreview.setSurfaceProvider(mCameraPreview.getSurfaceProvider());
    }


    /**
     * 绑定摄像头
     *
     * @param captureMode
     */
    private void bindCamera(int captureMode) {
        mCameraProvider.unbindAll(); // 重新绑定前要先解绑
        try {
            if (captureMode == MODE_PHOTO) {
                // 拍照
                // 把相机选择器、预览视图、图像捕捉器绑定到相机提供器的生命周期
                mCameraProvider.bindToLifecycle(mOwner, mCameraSelector, mPreview, mImageCapture);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 关闭相机
     */
    public void closeCamera() {
        mCameraProvider.unbindAll(); // 解绑相机提供器
        mExecutorService.shutdown(); // 关闭线程池
    }

    // 开始拍照
    public void takePicture() {
        if (mImageCapture == null) return;
        ImageCapture.Metadata metadata = new ImageCapture.Metadata();

        File file;

        // 构建图像捕捉器的输出选项
        ImageCapture.OutputFileOptions options =
                new ImageCapture.OutputFileOptions
                        .Builder(file = new File(rootPath, System.currentTimeMillis() + ".png"))
                        .setMetadata(metadata)
                        .build();
        /**
         * 执行拍照动作
         */
        mImageCapture.takePicture(options, mExecutorService, new ImageCapture.OnImageSavedCallback() {
            @Override
            public void onImageSaved(ImageCapture.OutputFileResults outputFileResults) {
                mStopListener.onStop(0, file.getAbsolutePath());
            }

            @Override
            public void onError(ImageCaptureException exception) {
                mStopListener.onStop(-1, "拍摄失败，错误信息为：" + exception.getMessage());
            }
        });
    }


    /**
     * 是否是前置
     *
     * @return
     */
    public boolean isCameraFRONT() {
        return mCameraType == CameraSelector.LENS_FACING_FRONT;
    }


    /**
     * 图像镜像问题
     *
     * @param bitmap
     * @return
     */
    public Bitmap MirrorImage(Bitmap bitmap) {
        Bitmap b = null;
        try {
            Matrix matrix = new Matrix();
            matrix.postScale(-1, 1);
            b = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } finally {
            bitmap.recycle();
        }
        return b;
    }


    /**
     * 保存
     *
     * @throws IOException
     */
    private void save(File f) {
        FileOutputStream os = null;
        try {
            os = new FileOutputStream(f);
            BufferedOutputStream bos = new BufferedOutputStream(os);

            Bitmap b = BitmapFactory.decodeFile(f.getAbsolutePath());

            if (b == null) return;

            if (isCameraFRONT()) {
                b = MirrorImage(b);
            }

            b.compress(Bitmap.CompressFormat.PNG, 100, bos);

            bos.flush();
            bos.close();
            os.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
